import React, { Component } from 'react'
import { Modal } from 'antd-mobile'
import Sockette from 'sockette'
import AI from './AI'
import config from '../utils/config'

const { 图片地址, 接口网址 } = config

const 起始布局 = [
    ['C0', 'M0', 'X0', 'S0', 'J0', 'S1', 'X1', 'M1', 'C1'],
    [, , , , , , , ,],
    [, 'P0', , , , , , 'P1',],
    ['Z0', , 'Z1', , 'Z2', , 'Z3', , 'Z4'],
    [, , , , , , , ,],
    [, , , , , , , ,],
    ['z0', , 'z1', , 'z2', , 'z3', , 'z4'],
    [, 'p0', , , , , , 'p1',],
    [, , , , , , , ,],
    ['c0', 'm0', 'x0', 's0', 'j0', 's1', 'x1', 'm1', 'c1']
]

const 二维数组克隆 = (arr) => {
    let newArr = [];
    for (let i = 0; i < arr.length; i++) {
        newArr[i] = arr[i].slice();
    }
    return newArr;
}

let 棋盘宽 = 325
let 棋盘高 = 402
let canvas = {}
let ct = {}
let 格宽 = 35
let 格高 = 36
let 着点X = 5
let 着点Y = 19
let 棋子映射 = {}
let 棋子坐标 = 二维数组克隆(起始布局)
let 图片 = {
    背景图片: new Image(),
    提示点: new Image(),
    外框: new Image()
}
let 棋子图片 = {}
let 当前棋子 = undefined
let 可着点 = []
let 最近走棋 = {}
let 正在下棋 = true
let 搜索深度 = 4
let 棋盘
let 阵营 = 1 // 1:红方,-1:蓝方
let ws // websocket

const 棋子能走的着点 = {}

//车
棋子能走的着点.c = (x, y, id, 棋子坐标) => {
    var d = [];
    //左侧检索
    for (var i = x - 1; i >= 0; i--) {
        if (棋子坐标[y][i]) {
            if (棋子映射[棋子坐标[y][i]].id != id) d.push([i, y]);
            break
        } else {
            d.push([i, y])
        }
    }
    //右侧检索
    for (var i = x + 1; i <= 8; i++) {
        if (棋子坐标[y][i]) {
            if (棋子映射[棋子坐标[y][i]].id != id) d.push([i, y]);
            break
        } else {
            d.push([i, y])
        }
    }
    //上检索
    for (var i = y - 1; i >= 0; i--) {
        if (棋子坐标[i][x]) {
            if (棋子映射[棋子坐标[i][x]].id != id) d.push([x, i]);
            break
        } else {
            d.push([x, i])
        }
    }
    //下检索
    for (var i = y + 1; i <= 9; i++) {
        if (棋子坐标[i][x]) {
            if (棋子映射[棋子坐标[i][x]].id != id) d.push([x, i]);
            break
        } else {
            d.push([x, i])
        }
    }
    return d;
}

//马
棋子能走的着点.m = (x, y, id, 棋子坐标) => {
    var d = [];
    //1点
    if (y - 2 >= 0 && x + 1 <= 8 && !棋子坐标[y - 1][x] && (!棋子映射[棋子坐标[y - 2][x + 1]] || 棋子映射[棋子坐标[y - 2][x + 1]].id != id)) d.push([x + 1, y - 2]);
    //2点
    if (y - 1 >= 0 && x + 2 <= 8 && !棋子坐标[y][x + 1] && (!棋子映射[棋子坐标[y - 1][x + 2]] || 棋子映射[棋子坐标[y - 1][x + 2]].id != id)) d.push([x + 2, y - 1]);
    //4点
    if (y + 1 <= 9 && x + 2 <= 8 && !棋子坐标[y][x + 1] && (!棋子映射[棋子坐标[y + 1][x + 2]] || 棋子映射[棋子坐标[y + 1][x + 2]].id != id)) d.push([x + 2, y + 1]);
    //5点
    if (y + 2 <= 9 && x + 1 <= 8 && !棋子坐标[y + 1][x] && (!棋子映射[棋子坐标[y + 2][x + 1]] || 棋子映射[棋子坐标[y + 2][x + 1]].id != id)) d.push([x + 1, y + 2]);
    //7点
    if (y + 2 <= 9 && x - 1 >= 0 && !棋子坐标[y + 1][x] && (!棋子映射[棋子坐标[y + 2][x - 1]] || 棋子映射[棋子坐标[y + 2][x - 1]].id != id)) d.push([x - 1, y + 2]);
    //8点
    if (y + 1 <= 9 && x - 2 >= 0 && !棋子坐标[y][x - 1] && (!棋子映射[棋子坐标[y + 1][x - 2]] || 棋子映射[棋子坐标[y + 1][x - 2]].id != id)) d.push([x - 2, y + 1]);
    //10点
    if (y - 1 >= 0 && x - 2 >= 0 && !棋子坐标[y][x - 1] && (!棋子映射[棋子坐标[y - 1][x - 2]] || 棋子映射[棋子坐标[y - 1][x - 2]].id != id)) d.push([x - 2, y - 1]);
    //11点
    if (y - 2 >= 0 && x - 1 >= 0 && !棋子坐标[y - 1][x] && (!棋子映射[棋子坐标[y - 2][x - 1]] || 棋子映射[棋子坐标[y - 2][x - 1]].id != id)) d.push([x - 1, y - 2]);

    return d;
}

//相
棋子能走的着点.x = (x, y, id, 棋子坐标) => {
    var d = [];
    if (id === 1) { //红方
        //4点半
        if (y + 2 <= 9 && x + 2 <= 8 && !棋子坐标[y + 1][x + 1] && (!棋子映射[棋子坐标[y + 2][x + 2]] || 棋子映射[棋子坐标[y + 2][x + 2]].id != id)) d.push([x + 2, y + 2]);
        //7点半
        if (y + 2 <= 9 && x - 2 >= 0 && !棋子坐标[y + 1][x - 1] && (!棋子映射[棋子坐标[y + 2][x - 2]] || 棋子映射[棋子坐标[y + 2][x - 2]].id != id)) d.push([x - 2, y + 2]);
        //1点半
        if (y - 2 >= 5 && x + 2 <= 8 && !棋子坐标[y - 1][x + 1] && (!棋子映射[棋子坐标[y - 2][x + 2]] || 棋子映射[棋子坐标[y - 2][x + 2]].id != id)) d.push([x + 2, y - 2]);
        //10点半
        if (y - 2 >= 5 && x - 2 >= 0 && !棋子坐标[y - 1][x - 1] && (!棋子映射[棋子坐标[y - 2][x - 2]] || 棋子映射[棋子坐标[y - 2][x - 2]].id != id)) d.push([x - 2, y - 2]);
    } else {
        //4点半
        if (y + 2 <= 4 && x + 2 <= 8 && !棋子坐标[y + 1][x + 1] && (!棋子映射[棋子坐标[y + 2][x + 2]] || 棋子映射[棋子坐标[y + 2][x + 2]].id != id)) d.push([x + 2, y + 2]);
        //7点半
        if (y + 2 <= 4 && x - 2 >= 0 && !棋子坐标[y + 1][x - 1] && (!棋子映射[棋子坐标[y + 2][x - 2]] || 棋子映射[棋子坐标[y + 2][x - 2]].id != id)) d.push([x - 2, y + 2]);
        //1点半
        if (y - 2 >= 0 && x + 2 <= 8 && !棋子坐标[y - 1][x + 1] && (!棋子映射[棋子坐标[y - 2][x + 2]] || 棋子映射[棋子坐标[y - 2][x + 2]].id != id)) d.push([x + 2, y - 2]);
        //10点半
        if (y - 2 >= 0 && x - 2 >= 0 && !棋子坐标[y - 1][x - 1] && (!棋子映射[棋子坐标[y - 2][x - 2]] || 棋子映射[棋子坐标[y - 2][x - 2]].id != id)) d.push([x - 2, y - 2]);
    }
    return d;
}

//士
棋子能走的着点.s = (x, y, id, 棋子坐标) => {
    var d = [];
    if (id === 1) { //红方
        //4点半
        if (y + 1 <= 9 && x + 1 <= 5 && (!棋子映射[棋子坐标[y + 1][x + 1]] || 棋子映射[棋子坐标[y + 1][x + 1]].id != id)) d.push([x + 1, y + 1]);
        //7点半
        if (y + 1 <= 9 && x - 1 >= 3 && (!棋子映射[棋子坐标[y + 1][x - 1]] || 棋子映射[棋子坐标[y + 1][x - 1]].id != id)) d.push([x - 1, y + 1]);
        //1点半
        if (y - 1 >= 7 && x + 1 <= 5 && (!棋子映射[棋子坐标[y - 1][x + 1]] || 棋子映射[棋子坐标[y - 1][x + 1]].id != id)) d.push([x + 1, y - 1]);
        //10点半
        if (y - 1 >= 7 && x - 1 >= 3 && (!棋子映射[棋子坐标[y - 1][x - 1]] || 棋子映射[棋子坐标[y - 1][x - 1]].id != id)) d.push([x - 1, y - 1]);
    } else {
        //4点半
        if (y + 1 <= 2 && x + 1 <= 5 && (!棋子映射[棋子坐标[y + 1][x + 1]] || 棋子映射[棋子坐标[y + 1][x + 1]].id != id)) d.push([x + 1, y + 1]);
        //7点半
        if (y + 1 <= 2 && x - 1 >= 3 && (!棋子映射[棋子坐标[y + 1][x - 1]] || 棋子映射[棋子坐标[y + 1][x - 1]].id != id)) d.push([x - 1, y + 1]);
        //1点半
        if (y - 1 >= 0 && x + 1 <= 5 && (!棋子映射[棋子坐标[y - 1][x + 1]] || 棋子映射[棋子坐标[y - 1][x + 1]].id != id)) d.push([x + 1, y - 1]);
        //10点半
        if (y - 1 >= 0 && x - 1 >= 3 && (!棋子映射[棋子坐标[y - 1][x - 1]] || 棋子映射[棋子坐标[y - 1][x - 1]].id != id)) d.push([x - 1, y - 1]);
    }
    return d;

}

//将
棋子能走的着点.j = (x, y, id, 棋子坐标) => {
    var d = [];
    var isNull = (function () {
        var y1 = 棋子映射["j0"].y;
        var x1 = 棋子映射["J0"].x;
        var y2 = 棋子映射["J0"].y;
        for (var i = y1 - 1; i > y2; i--) {
            if (棋子坐标[i][x1]) return false;
        }
        return true;
    })();

    if (id === 1) { //红方
        //下
        if (y + 1 <= 9 && (!棋子映射[棋子坐标[y + 1][x]] || 棋子映射[棋子坐标[y + 1][x]].id != id)) d.push([x, y + 1]);
        //上
        if (y - 1 >= 7 && (!棋子映射[棋子坐标[y - 1][x]] || 棋子映射[棋子坐标[y - 1][x]].id != id)) d.push([x, y - 1]);
        //老将对老将的情况
        if (棋子映射["j0"].x == 棋子映射["J0"].x && isNull) d.push([棋子映射["J0"].x, 棋子映射["J0"].y]);

    } else {
        //下
        if (y + 1 <= 2 && (!棋子映射[棋子坐标[y + 1][x]] || 棋子映射[棋子坐标[y + 1][x]].id != id)) d.push([x, y + 1]);
        //上
        if (y - 1 >= 0 && (!棋子映射[棋子坐标[y - 1][x]] || 棋子映射[棋子坐标[y - 1][x]].id != id)) d.push([x, y - 1]);
        //老将对老将的情况
        if (棋子映射["j0"].x == 棋子映射["J0"].x && isNull) d.push([棋子映射["j0"].x, 棋子映射["j0"].y]);
    }
    //右
    if (x + 1 <= 5 && (!棋子映射[棋子坐标[y][x + 1]] || 棋子映射[棋子坐标[y][x + 1]].id != id)) d.push([x + 1, y]);
    //左
    if (x - 1 >= 3 && (!棋子映射[棋子坐标[y][x - 1]] || 棋子映射[棋子坐标[y][x - 1]].id != id)) d.push([x - 1, y]);
    return d;
}

//炮
棋子能走的着点.p = (x, y, id, 棋子坐标) => {
    var d = [];
    //左侧检索
    var n = 0;
    for (var i = x - 1; i >= 0; i--) {
        if (棋子坐标[y][i]) {
            if (n == 0) {
                n++;
                continue;
            } else {
                if (棋子映射[棋子坐标[y][i]].id != id) d.push([i, y]);
                break
            }
        } else {
            if (n == 0) d.push([i, y])
        }
    }
    //右侧检索
    var n = 0;
    for (var i = x + 1; i <= 8; i++) {
        if (棋子坐标[y][i]) {
            if (n == 0) {
                n++;
                continue;
            } else {
                if (棋子映射[棋子坐标[y][i]].id != id) d.push([i, y]);
                break
            }
        } else {
            if (n == 0) d.push([i, y])
        }
    }
    //上检索
    var n = 0;
    for (var i = y - 1; i >= 0; i--) {
        if (棋子坐标[i][x]) {
            if (n == 0) {
                n++;
                continue;
            } else {
                if (棋子映射[棋子坐标[i][x]].id != id) d.push([x, i]);
                break
            }
        } else {
            if (n == 0) d.push([x, i])
        }
    }
    //下检索
    var n = 0;
    for (var i = y + 1; i <= 9; i++) {
        if (棋子坐标[i][x]) {
            if (n == 0) {
                n++;
                continue;
            } else {
                if (棋子映射[棋子坐标[i][x]].id != id) d.push([x, i]);
                break
            }
        } else {
            if (n == 0) d.push([x, i])
        }
    }
    return d;
}

//卒
棋子能走的着点.z = (x, y, id, 棋子坐标) => {
    var d = [];
    if (id === 1) { //红方
        //上
        if (y - 1 >= 0 && (!棋子映射[棋子坐标[y - 1][x]] || 棋子映射[棋子坐标[y - 1][x]].id != id)) d.push([x, y - 1]);
        //右
        if (x + 1 <= 8 && y <= 4 && (!棋子映射[棋子坐标[y][x + 1]] || 棋子映射[棋子坐标[y][x + 1]].id != id)) d.push([x + 1, y]);
        //左
        if (x - 1 >= 0 && y <= 4 && (!棋子映射[棋子坐标[y][x - 1]] || 棋子映射[棋子坐标[y][x - 1]].id != id)) d.push([x - 1, y]);
    } else {
        //下
        if (y + 1 <= 9 && (!棋子映射[棋子坐标[y + 1][x]] || 棋子映射[棋子坐标[y + 1][x]].id != id)) d.push([x, y + 1]);
        //右
        if (x + 1 <= 8 && y >= 6 && (!棋子映射[棋子坐标[y][x + 1]] || 棋子映射[棋子坐标[y][x + 1]].id != id)) d.push([x + 1, y]);
        //左
        if (x - 1 >= 0 && y >= 6 && (!棋子映射[棋子坐标[y][x - 1]] || 棋子映射[棋子坐标[y][x - 1]].id != id)) d.push([x - 1, y]);
    }

    return d;
}

const 棋子配置 = {
    //红子 中文/图片地址/阵营/种类
    'c': { text: "车", img: 'r_c', id: 1, 种类: "c" },
    'm': { text: "马", img: 'r_m', id: 1, 种类: "m" },
    'x': { text: "相", img: 'r_x', id: 1, 种类: "x" },
    's': { text: "仕", img: 'r_s', id: 1, 种类: "s" },
    'j': { text: "将", img: 'r_j', id: 1, 种类: "j" },
    'p': { text: "炮", img: 'r_p', id: 1, 种类: "p" },
    'z': { text: "兵", img: 'r_z', id: 1, 种类: "z" },

    //蓝子
    'C': { text: "車", img: 'b_c', id: -1, 种类: "c" },
    'M': { text: "馬", img: 'b_m', id: -1, 种类: "m" },
    'X': { text: "象", img: 'b_x', id: -1, 种类: "x" },
    'S': { text: "士", img: 'b_s', id: -1, 种类: "s" },
    'J': { text: "帅", img: 'b_j', id: -1, 种类: "j" },
    'P': { text: "炮", img: 'b_p', id: -1, 种类: "p" },
    'Z': { text: "卒", img: 'b_z', id: -1, 种类: "z" }
}

const 点击棋盘 = (e) => {
    if (!正在下棋 || 最近走棋.F阵营 == 阵营) {
        return
    }
    if (!ws.isConnect) {
        return
    }
    let { x, y } = 获取点击点(e);
    let key = 获取点击棋子(x, y);

    if (key) {
        点击棋子(key, x, y);
    } else if (当前棋子) {
        走棋(x, y);
    }
}

const 获取点击棋子 = (x, y) => {
    if (x < 0 || x > 8 || y < 0 || y > 9) {
        return false;
    }
    return (棋子坐标[y][x] && 棋子坐标[y][x] != "0") ? 棋子坐标[y][x] : false;
}

const 获取点击点 = (e) => {
    let { x, y } = 获取画布位置();
    x = Math.round((e.pageX - x - 着点X - 20) / 格宽)
    y = Math.round((e.pageY - y - 着点Y - 20) / 格高)
    return { "x": x, "y": y }
}

const 获取画布位置 = () => {
    let left = canvas.offsetLeft
    let top = canvas.offsetTop
    let current = canvas.offsetParent
    while (current !== null) {
        left += current.offsetLeft
        top += current.offsetTop
        current = current.offsetParent
    }
    return { x: left, y: top }
}

const 点击棋子 = (key, x, y) => {
    let 棋子 = 棋子映射[key]
    //吃子
    if (当前棋子 && 当前棋子.key != key && 棋子.id != 棋子映射[当前棋子.key].id && 检测是否可着点(x, y)) {
        delete 棋子映射[key]
        棋子映射[当前棋子.key].alpha = 1
        棋子映射[当前棋子.key].x = x
        棋子映射[当前棋子.key].y = y
        delete 棋子坐标[当前棋子.y][当前棋子.x]
        棋子坐标[y][x] = 当前棋子.key
        let oldX = 当前棋子.x
        let oldY = 当前棋子.y
        当前棋子 = undefined
        可着点 = []
        发送数据("走棋", 阵营, oldX, oldY, x, y)
        显示()
        if (key == "j0") {
            棋盘.蓝方获胜()
            正在下棋 = false
        }
        if (key == "J0") {
            棋盘.红方获胜()
            正在下棋 = false
        }
    } else if (棋子.id == 阵营) { // 选中棋子
        棋子.alpha = 0.6
        if (当前棋子) {
            棋子映射[当前棋子.key].alpha = 1
        }
        当前棋子 = { ...棋子 }
        可着点 = 棋子能走的着点[棋子配置[key.slice(0, 1)].种类](x, y, 棋子.id, 棋子坐标)
        显示()
    }
}

const 走棋 = (x, y) => {
    var key = 当前棋子.key;
    if (key && 检测是否可着点(x, y)) {
        delete 棋子坐标[当前棋子.y][当前棋子.x];
        棋子坐标[y][x] = key;
        可着点 = []
        棋子映射[key].x = x
        棋子映射[key].y = y
        棋子映射[key].alpha = 1
        let oldX = 当前棋子.x
        let oldY = 当前棋子.y
        当前棋子 = undefined
        可着点 = []
        发送数据("走棋", 阵营, oldX, oldY, x, y)
        显示()
    }
}
// F类型: 走棋/悔棋/重开/设置阵营
const 发送数据 = (F类型, F阵营, OldX, OldY, NewX, NewY) => {
    if (ws.isConnect) {
        ws.send(JSON.stringify({ F类型, F阵营: F阵营, OldX, OldY, NewX, NewY }))
    }
}

const 检测是否可着点 = (x, y) => {
    for (let i = 0; i < 可着点.length; i++) {
        if (可着点[i][0] == x && 可着点[i][1] == y) {
            return true
        }
    }
    return false
}

const 显示 = () => {
    ct.clearRect(0, 0, 棋盘宽, 棋盘高)

    // 绘制背景
    ct.drawImage(图片.背景图片, 0, 0)

    // 绘制棋子
    for (let key in 棋子映射) {
        const { x, y, alpha } = 棋子映射[key]
        ct.globalAlpha = alpha ? alpha : 1
        ct.drawImage(棋子图片[key.slice(0, 1)], x * 格宽 + 着点X, y * 格高 + 着点Y)
    }

    // 绘制可着点
    for (let i = 0; i < 可着点.length; i++) {
        ct.drawImage(图片.提示点, 可着点[i][0] * 格宽 + 着点X + 10, 可着点[i][1] * 格高 + 着点Y + 10)
    }

    // 绘制最近走棋
    const { OldX, OldY, NewX, NewY } = 最近走棋
    if (OldX || OldY || NewX || NewY) {
        ct.drawImage(图片.外框, OldX * 格宽 + 着点X, OldY * 格高 + 着点Y)
        ct.drawImage(图片.外框, NewX * 格宽 + 着点X, NewY * 格高 + 着点Y)
    }

}
const 棋子Id = (key) => {
    return 棋子配置[key.slice(0, 1)].id
}
const getGuid = () => {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
class App extends Component {
    constructor(props) {
        super(props)
    }
    componentDidMount = () => {
        棋盘 = this
        canvas = document.getElementById("画布")
        ct = canvas.getContext("2d")

        图片.背景图片.src = 图片地址 + "img/stype_1/bg.png"
        图片.提示点.src = 图片地址 + "img/stype_1/dot.png"
        图片.外框.src = 图片地址 + "img/stype_1/r_box.png"

        for (let key in 棋子配置) {
            const img = new Image()
            img.src = 图片地址 + "img/stype_1/" + 棋子配置[key].img + ".png"
            棋子图片[key] = img
        }

        let guid = localStorage.guid
        if (!guid) {
            guid = getGuid()
            localStorage.guid = guid
        }
        ws = new Sockette(接口网址.replace("http", "ws") + "/ws?guid=" + guid, {
            timeout: 5e3,
            maxAttempts: 10,
            onopen: e => {
                ws.isConnect = true
                发送数据("设置阵营", 阵营)
            },
            onmessage: e => {
                let data = JSON.parse(e.data)
                棋子映射 = data.棋子映射
                棋子坐标 = data.棋子坐标
                最近走棋 = data.最近走棋
                for (let key in 棋子映射) {
                    棋子映射[key].id = 棋子Id(key)
                }
                显示()
            },
            onreconnect: e => { },
            onmaximum: e => { },
            onclose: e => {
                ws.isConnect = false
            },
            onerror: e => { }
        })
    }
    初始化 = (阵营1) => {
        阵营 = 阵营1
        发送数据("设置阵营", 阵营)
    }
    开始 = (布局) => {
        发送数据("重开")
    }
    悔棋 = () => {
        发送数据("悔棋")
    }
    蓝方获胜 = () => {
        Modal.alert("蓝方获胜", "是否再来一局?", [{
            text: "是",
            onPress: _ => {
                this.开始()
            }
        }, {
            text: "悔棋",
            onPress: _ => {
                this.悔棋()
            }
        }])
    }
    红方获胜 = () => {
        Modal.alert("红方", "是否再来一局?", [{
            text: "是",
            onPress: _ => {
                this.开始()
            }
        }, {
            text: "悔棋",
            onPress: _ => {
                this.悔棋()
            }
        }])
    }
    render() {
        return (
            <div style={{ width: 棋盘宽, height: 棋盘高 }}>
                <canvas id="画布" width={棋盘宽} height={棋盘高} onClick={点击棋盘}>
                    对不起，您的浏览器不支持HTML5，请升级浏览器至IE9、firefox或者谷歌浏览器！
                </canvas>
            </div>
        )
    }
}

export default App